# 内置库
import urllib
import json
import re

# 第三方库
import requests
from bs4 import BeautifulSoup

# 本地库
from movie_spider.utils.save_items import save_items
from .config import spider_source, request_headers
from .utils import parser
from .models import Movie, MovieList

MovieList
class Spider:
    """
    该类接收数据源参数，数据源参数定义在config文件夹下的spider_source.py
    """

    def __init__(self, source='default'):
        self.source = spider_source.sources[source]

    @save_items
    def search(self, keyword,save=None):
        if not keyword:
            return "关键词不能为空"

        result_list = []

        url = self.source['search_url'].format(urllib.parse.quote(keyword.encode('gb2312')))
        response = self.send_http(url=url)
        if response:
            movie_list = self._get_movie_result(response)
            result_list += movie_list

        return MovieList([Movie(movie['name'], movie['href'], self) for movie in result_list])

    def _get_movie_result(self, response):

        html = self.get_decoded_html(response)
        movie_list = []

        movie_list_ele = html.select('div.co_content8')[0].select('ul')[0]
        tables = movie_list_ele.select('table')

        for table in tables:
            a_ele = table.select('a')
            if a_ele:
                href = a_ele[0]['href']
                if "TotalResult" not in href:
                    name = a_ele[0].text
                    movie_list.append(dict(
                        name=name,
                        href=href
                    ))

        next_page_ele = movie_list_ele.find(text="下一页", href=True)

        if next_page_ele:
            next_url = parser.join_path_to_hostname(self.source['base_url'], next_page_ele['href'])
            next_page_response = self.send_http(url=next_url)

            tmp_list = self._get_movie_result(next_page_response)
            if tmp_list:
                movie_list += tmp_list

        return movie_list

    def send_http(self, url, rtype='GET', **kwargs):
        """
        该函数包装了requests的请求，进行get和post请求

        :param url:请求的URL地址
        :param rtype:请求的类型，例如GET和POST
        :param kwargs:传入的形参，例如data和params
        :return:返回一个requests的response对象
        """
        data = kwargs.get('data', {})
        params = kwargs.get('params', {})
        host = kwargs.get('host')
        if not host:
            host = self.source['host']

        headers = {
            "User-Agent": request_headers.useragent,
            "HOST": host,
            "Cookie": request_headers.cookie,
            "Accept": request_headers.accept,
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Pragma": "no-cache",
            "Upgrade-Insecure-Requests": "1",
            "Content-Range":"bytes=0-100000"
        }
        if rtype == "GET":
            response = requests.get(url, headers=headers, params=params, stream=True)

            return response
        elif rtype == "POST":
            response = requests.get(url, headers=headers, data=json.dumps(data), params=params)
            return response

    def get_decoded_html(self, response):
        """
        该函数接收一个requests的response对象
        并根据对应的字符编码返回一个Beautifulsoup对象
        :param response: requests的response对象
        :return: Beautifulsoup对象
        """

        if response.status_code == 200 or response.status_code == 206:

            try:
                html = response.content.decode("utf-8")
            except UnicodeDecodeError:
                try:
                    html = response.content.decode("gb2312", "ignore")
                except UnicodeDecodeError:
                    html = response.content.decode("gbk", "ignore")

            return BeautifulSoup(html, "html.parser")
